/*
 * Jay9DownloaderView.java
 */

package jay9downloader;

import java.awt.Desktop;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFileChooser;
import org.jdesktop.application.Action;
import org.jdesktop.application.ResourceMap;
import org.jdesktop.application.SingleFrameApplication;
import org.jdesktop.application.Task;
import org.jdesktop.application.TaskMonitor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.net.URI;
import javax.swing.Timer;
import javax.swing.Icon;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.RowFilter;
import org.jdesktop.application.FrameView;

/**
 * The application's main frame.
 */
public class Jay9DownloaderView extends FrameView implements VideoListener {

    public Jay9DownloaderView(SingleFrameApplication app) {
        super(app);
        initComponents();

        // status bar initialization - message timeout, idle icon and busy animation, etc
        ResourceMap resourceMap = getResourceMap();
        int messageTimeout = resourceMap.getInteger("StatusBar.messageTimeout");
        messageTimer = new Timer(messageTimeout, new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                statusMessageLabel.setText("");
            }
        });
        messageTimer.setRepeats(false);
        int busyAnimationRate = resourceMap.getInteger("StatusBar.busyAnimationRate");
        for (int i = 0; i < busyIcons.length; i++) {
            busyIcons[i] = resourceMap.getIcon("StatusBar.busyIcons[" + i + "]");
        }
        busyIconTimer = new Timer(busyAnimationRate, new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                busyIconIndex = (busyIconIndex + 1) % busyIcons.length;
                statusAnimationLabel.setIcon(busyIcons[busyIconIndex]);
            }
        });
        idleIcon = resourceMap.getIcon("StatusBar.idleIcon");
        statusAnimationLabel.setIcon(idleIcon);
        progressBar.setVisible(false);

        // connecting action tasks to status bar via TaskMonitor
        TaskMonitor taskMonitor = new TaskMonitor(getApplication().getContext());
        taskMonitor.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
            public void propertyChange(java.beans.PropertyChangeEvent evt) {
                String propertyName = evt.getPropertyName();
                if ("started".equals(propertyName)) {
                    if (!busyIconTimer.isRunning()) {
                        statusAnimationLabel.setIcon(busyIcons[0]);
                        busyIconIndex = 0;
                        busyIconTimer.start();
                    }
                    progressBar.setVisible(true);
                    progressBar.setIndeterminate(true);
                } else if ("done".equals(propertyName)) {
                    busyIconTimer.stop();
                    statusAnimationLabel.setIcon(idleIcon);
                    progressBar.setVisible(false);
                    progressBar.setValue(0);
                } else if ("message".equals(propertyName)) {
                    String text = (String)(evt.getNewValue());
                    statusMessageLabel.setText((text == null) ? "" : text);
                    messageTimer.restart();
                } else if ("progress".equals(propertyName)) {
                    int value = (Integer)(evt.getNewValue());
                    progressBar.setVisible(true);
                    progressBar.setIndeterminate(false);
                    progressBar.setValue(value);
                }
            }
        });
        
    }

    @Action
    public Task showAboutBox() {
        return new ShowAboutBoxTask(getApplication());
    }

    public void updateVideoFields() {
        textVideoName.setText(Video.getCurrentVideo().getTitle());
        textVideoUrl.setText(Video.getCurrentVideo().getUrl());
        textVideoDetails.setText(Video.getCurrentVideo().getDurationAsString() + ", " + Video.getCurrentVideo().getDimensions() + ", " + Video.getCurrentVideo().getTimestampAsDateFormattedString());
        textVideoComment.setText(Video.getCurrentVideo().getTimestampString());
    }
    
    private class ShowAboutBoxTask extends org.jdesktop.application.Task<Object, Void> {
        ShowAboutBoxTask(org.jdesktop.application.Application app) {
            // Runs on the EDT.  Copy GUI state that
            // doInBackground() depends on from parameters
            // to ShowAboutBoxTask fields, here.
            super(app);
            if (aboutBox == null) {
            JFrame mainFrame = Jay9DownloaderApp.getApplication().getMainFrame();
            aboutBox = new Jay9DownloaderAboutBox(mainFrame);
            aboutBox.setLocationRelativeTo(mainFrame);
            }
            Jay9DownloaderApp.getApplication().show(aboutBox);
        }
        @Override protected Object doInBackground() {
            // Your Task's code here.  This method runs
            // on a background thread, so don't reference
            // the Swing GUI from here.
            return null;  // return your result
        }
        @Override protected void succeeded(Object result) {
            // Runs on the EDT.  Update the GUI based on
            // the result computed by doInBackground().
        }
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        panelMain = new javax.swing.JPanel();
        panelAvailableVideos = new javax.swing.JPanel();
        videoScroll = new javax.swing.JScrollPane();
        videoList = new jay9downloader.VideoList();
        creditLink1 = new javax.swing.JLabel();
        creditLink2 = new javax.swing.JLabel();
        filterTextField = new javax.swing.JTextField();
        buttonAddVideo = new javax.swing.JButton();
        panelCurrentVideo = new javax.swing.JPanel();
        labelVideoName = new javax.swing.JLabel();
        labelVideoUrl = new javax.swing.JLabel();
        labelVideoDetails = new javax.swing.JLabel();
        labelVideoComment = new javax.swing.JLabel();
        textVideoComment = new javax.swing.JTextField();
        textVideoDetails = new javax.swing.JTextField();
        textVideoUrl = new javax.swing.JTextField();
        textVideoName = new javax.swing.JTextField();
        panelSelectedVideos = new javax.swing.JPanel();
        jScrollPane2 = new javax.swing.JScrollPane();
        videoTable1 = new jay9downloader.VideoTable();
        labelDownloadDirectory = new javax.swing.JLabel();
        textDownloadDirectory = new javax.swing.JTextField();
        buttonStartDownloading = new javax.swing.JButton();
        buttonRemoveVideo = new javax.swing.JButton();
        menuBar = new javax.swing.JMenuBar();
        javax.swing.JMenu fileMenu = new javax.swing.JMenu();
        javax.swing.JMenuItem exitMenuItem = new javax.swing.JMenuItem();
        javax.swing.JMenu helpMenu = new javax.swing.JMenu();
        aboutMenuItem = new javax.swing.JMenuItem();
        jMenu1 = new javax.swing.JMenu();
        jMenuItem1 = new javax.swing.JMenuItem();
        statusPanel = new javax.swing.JPanel();
        javax.swing.JSeparator statusPanelSeparator = new javax.swing.JSeparator();
        statusMessageLabel = new javax.swing.JLabel();
        statusAnimationLabel = new javax.swing.JLabel();
        progressBar = new javax.swing.JProgressBar();

        panelMain.setName("panelMain"); // NOI18N

        panelAvailableVideos.setBorder(javax.swing.BorderFactory.createTitledBorder("Available videos:"));
        panelAvailableVideos.setName("panelAvailableVideos"); // NOI18N
        panelAvailableVideos.setPreferredSize(new java.awt.Dimension(0, 0));

        videoScroll.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
        videoScroll.setName("videoScroll"); // NOI18N
        videoScroll.setPreferredSize(new java.awt.Dimension(0, 0));

        videoList.setModel(new Videos());
        videoList.setName("videoList"); // NOI18N
        videoList.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
            public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
                videoListValueChanged(evt);
            }
        });
        videoScroll.setViewportView(videoList);

        org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(jay9downloader.Jay9DownloaderApp.class).getContext().getResourceMap(Jay9DownloaderView.class);
        creditLink1.setText(resourceMap.getString("creditLink1.text")); // NOI18N
        creditLink1.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
        creditLink1.setName("creditLink1"); // NOI18N
        creditLink1.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                creditLink1MouseClicked(evt);
            }
        });

        creditLink2.setText(resourceMap.getString("creditLink2.text")); // NOI18N
        creditLink2.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
        creditLink2.setName("creditLink2"); // NOI18N
        creditLink2.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                creditLink2MouseClicked(evt);
            }
        });

        filterTextField.setText(resourceMap.getString("filterTextField.text")); // NOI18N
        filterTextField.setName("filterTextField"); // NOI18N
        filterTextField.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyTyped(java.awt.event.KeyEvent evt) {
                filterTextFieldKeyTyped(evt);
            }
        });

        buttonAddVideo.setText("Add video(s)"); // NOI18N
        buttonAddVideo.setName("buttonAddVideo"); // NOI18N
        buttonAddVideo.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                buttonAddVideoMouseReleased(evt);
            }
        });

        javax.swing.GroupLayout panelAvailableVideosLayout = new javax.swing.GroupLayout(panelAvailableVideos);
        panelAvailableVideos.setLayout(panelAvailableVideosLayout);
        panelAvailableVideosLayout.setHorizontalGroup(
            panelAvailableVideosLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, panelAvailableVideosLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(panelAvailableVideosLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addComponent(videoScroll, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 513, Short.MAX_VALUE)
                    .addGroup(panelAvailableVideosLayout.createSequentialGroup()
                        .addComponent(creditLink1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGap(18, 18, 18)
                        .addComponent(buttonAddVideo, javax.swing.GroupLayout.DEFAULT_SIZE, 316, Short.MAX_VALUE)
                        .addGap(18, 18, 18)
                        .addComponent(creditLink2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addComponent(filterTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 513, Short.MAX_VALUE))
                .addContainerGap())
        );
        panelAvailableVideosLayout.setVerticalGroup(
            panelAvailableVideosLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, panelAvailableVideosLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(filterTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(videoScroll, javax.swing.GroupLayout.DEFAULT_SIZE, 408, Short.MAX_VALUE)
                .addGap(18, 18, 18)
                .addGroup(panelAvailableVideosLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(creditLink1, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(creditLink2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(buttonAddVideo))
                .addContainerGap())
        );

        panelCurrentVideo.setBorder(javax.swing.BorderFactory.createTitledBorder("Current video:"));
        panelCurrentVideo.setName("panelCurrentVideo"); // NOI18N

        labelVideoName.setLabelFor(textVideoName);
        labelVideoName.setText("Name:"); // NOI18N
        labelVideoName.setName("labelVideoName"); // NOI18N

        labelVideoUrl.setLabelFor(textVideoUrl);
        labelVideoUrl.setText("URL:"); // NOI18N
        labelVideoUrl.setName("labelVideoUrl"); // NOI18N

        labelVideoDetails.setLabelFor(textVideoDetails);
        labelVideoDetails.setText("Details:"); // NOI18N
        labelVideoDetails.setName("labelVideoDetails"); // NOI18N

        labelVideoComment.setLabelFor(textVideoComment);
        labelVideoComment.setText("Comment:"); // NOI18N
        labelVideoComment.setName("labelVideoComment"); // NOI18N

        textVideoComment.setEditable(false);
        textVideoComment.setName("textVideoComment"); // NOI18N

        textVideoDetails.setEditable(false);
        textVideoDetails.setText(resourceMap.getString("textVideoDetails.text")); // NOI18N
        textVideoDetails.setName("textVideoDetails"); // NOI18N

        textVideoUrl.setEditable(false);
        textVideoUrl.setText(resourceMap.getString("textVideoUrl.text")); // NOI18N
        textVideoUrl.setName("textVideoUrl"); // NOI18N

        textVideoName.setEditable(false);
        textVideoName.setText(resourceMap.getString("textVideoName.text")); // NOI18N
        textVideoName.setName("textVideoName"); // NOI18N

        javax.swing.GroupLayout panelCurrentVideoLayout = new javax.swing.GroupLayout(panelCurrentVideo);
        panelCurrentVideo.setLayout(panelCurrentVideoLayout);
        panelCurrentVideoLayout.setHorizontalGroup(
            panelCurrentVideoLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(panelCurrentVideoLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(panelCurrentVideoLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(labelVideoComment)
                    .addComponent(labelVideoDetails)
                    .addComponent(labelVideoUrl)
                    .addComponent(labelVideoName))
                .addGap(18, 18, 18)
                .addGroup(panelCurrentVideoLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(textVideoDetails, javax.swing.GroupLayout.DEFAULT_SIZE, 488, Short.MAX_VALUE)
                    .addComponent(textVideoComment, javax.swing.GroupLayout.DEFAULT_SIZE, 488, Short.MAX_VALUE)
                    .addComponent(textVideoUrl, javax.swing.GroupLayout.DEFAULT_SIZE, 488, Short.MAX_VALUE)
                    .addComponent(textVideoName, javax.swing.GroupLayout.DEFAULT_SIZE, 488, Short.MAX_VALUE))
                .addContainerGap())
        );
        panelCurrentVideoLayout.setVerticalGroup(
            panelCurrentVideoLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(panelCurrentVideoLayout.createSequentialGroup()
                .addGroup(panelCurrentVideoLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(labelVideoName)
                    .addComponent(textVideoName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(panelCurrentVideoLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(labelVideoUrl)
                    .addComponent(textVideoUrl, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(panelCurrentVideoLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(labelVideoDetails)
                    .addComponent(textVideoDetails, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(panelCurrentVideoLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(labelVideoComment)
                    .addComponent(textVideoComment, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        panelSelectedVideos.setBorder(javax.swing.BorderFactory.createTitledBorder("Selected videos:"));
        panelSelectedVideos.setName("panelSelectedVideos"); // NOI18N

        jScrollPane2.setName("jScrollPane2"); // NOI18N

        videoTable1.setEditable(false);
        videoTable1.setName("videoTable1"); // NOI18N
        videoTable1.setRowHeight(30);
        videoTable1.setShowGrid(true);
        videoTable1.setShowVerticalLines(false);
        jScrollPane2.setViewportView(videoTable1);

        labelDownloadDirectory.setText("Download directory:"); // NOI18N
        labelDownloadDirectory.setName("labelDownloadDirectory"); // NOI18N

        textDownloadDirectory.setText(System.getProperty("user.dir") + System.getProperty("file.separator"));
        textDownloadDirectory.setName("textDownloadDirectory"); // NOI18N

        buttonStartDownloading.setText("Start Downloading"); // NOI18N
        buttonStartDownloading.setName("buttonStartDownloading"); // NOI18N
        buttonStartDownloading.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                buttonStartDownloadingMouseReleased(evt);
            }
        });

        buttonRemoveVideo.setText("Remove video(s)"); // NOI18N
        buttonRemoveVideo.setName("buttonRemoveVideo"); // NOI18N
        buttonRemoveVideo.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                buttonRemoveVideoMouseReleased(evt);
            }
        });

        javax.swing.GroupLayout panelSelectedVideosLayout = new javax.swing.GroupLayout(panelSelectedVideos);
        panelSelectedVideos.setLayout(panelSelectedVideosLayout);
        panelSelectedVideosLayout.setHorizontalGroup(
            panelSelectedVideosLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, panelSelectedVideosLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(panelSelectedVideosLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addComponent(jScrollPane2, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 328, Short.MAX_VALUE)
                    .addGroup(panelSelectedVideosLayout.createSequentialGroup()
                        .addComponent(labelDownloadDirectory)
                        .addGap(18, 18, 18)
                        .addComponent(textDownloadDirectory, javax.swing.GroupLayout.DEFAULT_SIZE, 213, Short.MAX_VALUE))
                    .addGroup(panelSelectedVideosLayout.createSequentialGroup()
                        .addComponent(buttonRemoveVideo)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 94, Short.MAX_VALUE)
                        .addComponent(buttonStartDownloading)))
                .addContainerGap())
        );
        panelSelectedVideosLayout.setVerticalGroup(
            panelSelectedVideosLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(panelSelectedVideosLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(panelSelectedVideosLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(labelDownloadDirectory)
                    .addComponent(textDownloadDirectory, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 261, Short.MAX_VALUE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(panelSelectedVideosLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(buttonStartDownloading)
                    .addComponent(buttonRemoveVideo))
                .addContainerGap())
        );

        javax.swing.GroupLayout panelMainLayout = new javax.swing.GroupLayout(panelMain);
        panelMain.setLayout(panelMainLayout);
        panelMainLayout.setHorizontalGroup(
            panelMainLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, panelMainLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(panelAvailableVideos, javax.swing.GroupLayout.PREFERRED_SIZE, 545, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(panelMainLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addComponent(panelSelectedVideos, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(panelCurrentVideo, javax.swing.GroupLayout.DEFAULT_SIZE, 360, Short.MAX_VALUE))
                .addContainerGap())
        );
        panelMainLayout.setVerticalGroup(
            panelMainLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(panelMainLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(panelMainLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(panelAvailableVideos, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 529, Short.MAX_VALUE)
                    .addGroup(panelMainLayout.createSequentialGroup()
                        .addComponent(panelCurrentVideo, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGap(18, 18, 18)
                        .addComponent(panelSelectedVideos, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
                .addContainerGap())
        );

        menuBar.setName("menuBar"); // NOI18N

        fileMenu.setText(resourceMap.getString("fileMenu.text")); // NOI18N
        fileMenu.setName("fileMenu"); // NOI18N

        javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance(jay9downloader.Jay9DownloaderApp.class).getContext().getActionMap(Jay9DownloaderView.class, this);
        exitMenuItem.setAction(actionMap.get("quit")); // NOI18N
        exitMenuItem.setName("exitMenuItem"); // NOI18N
        fileMenu.add(exitMenuItem);

        menuBar.add(fileMenu);

        helpMenu.setText(resourceMap.getString("helpMenu.text")); // NOI18N
        helpMenu.setName("helpMenu"); // NOI18N

        aboutMenuItem.setAction(actionMap.get("showAboutBox")); // NOI18N
        aboutMenuItem.setText(resourceMap.getString("aboutMenuItem.text")); // NOI18N
        aboutMenuItem.setName("aboutMenuItem"); // NOI18N
        helpMenu.add(aboutMenuItem);

        menuBar.add(helpMenu);

        jMenu1.setText("Links"); // NOI18N
        jMenu1.setName("jMenu1"); // NOI18N

        jMenuItem1.setText("day9tv.blip.tv"); // NOI18N
        jMenuItem1.setName("jMenuItem1"); // NOI18N
        jMenu1.add(jMenuItem1);

        menuBar.add(jMenu1);

        statusPanel.setName("statusPanel"); // NOI18N

        statusPanelSeparator.setName("statusPanelSeparator"); // NOI18N

        statusMessageLabel.setText(resourceMap.getString("statusMessageLabel.text")); // NOI18N
        statusMessageLabel.setName("statusMessageLabel"); // NOI18N

        statusAnimationLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
        statusAnimationLabel.setName("statusAnimationLabel"); // NOI18N

        progressBar.setName("progressBar"); // NOI18N

        javax.swing.GroupLayout statusPanelLayout = new javax.swing.GroupLayout(statusPanel);
        statusPanel.setLayout(statusPanelLayout);
        statusPanelLayout.setHorizontalGroup(
            statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(statusPanelSeparator, javax.swing.GroupLayout.DEFAULT_SIZE, 931, Short.MAX_VALUE)
            .addGroup(statusPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(statusMessageLabel)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 675, Short.MAX_VALUE)
                .addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(statusAnimationLabel)
                .addContainerGap())
        );
        statusPanelLayout.setVerticalGroup(
            statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(statusPanelLayout.createSequentialGroup()
                .addComponent(statusPanelSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 2, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addGroup(statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(statusMessageLabel)
                    .addComponent(statusAnimationLabel)
                    .addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(3, 3, 3))
        );

        setComponent(panelMain);
        setMenuBar(menuBar);
        setStatusBar(statusPanel);
    }// </editor-fold>//GEN-END:initComponents

    private void filterTextFieldKeyTyped(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_filterTextFieldKeyTyped
        if(evt.getSource().equals(filterTextField)) {
            videoList.setRowFilter(RowFilter.regexFilter("(?i)" + filterTextField.getText(), 0));
        }
}//GEN-LAST:event_filterTextFieldKeyTyped

    private void creditLink2MouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_creditLink2MouseClicked
        if(Desktop.isDesktopSupported()) {
            try {
                Desktop desktop = Desktop.getDesktop();
                desktop.browse(new URI(new Url(creditLink2.getText()).toString()));
            } catch (IOException ex) {
                Logger.getLogger(Jay9DownloaderView.class.getName()).log(Level.SEVERE, null, ex);
            } catch (URISyntaxException ex) {
                Logger.getLogger(Jay9DownloaderView.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
}//GEN-LAST:event_creditLink2MouseClicked

    private void creditLink1MouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_creditLink1MouseClicked
        if(Desktop.isDesktopSupported()) {
            try {
                Desktop desktop = Desktop.getDesktop();
                desktop.browse(new URI(new Url(creditLink1.getText()).toString()));
            } catch (IOException ex) {
                Logger.getLogger(Jay9DownloaderView.class.getName()).log(Level.SEVERE, null, ex);
            } catch (URISyntaxException ex) {
                Logger.getLogger(Jay9DownloaderView.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
}//GEN-LAST:event_creditLink1MouseClicked

    private void videoListValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_videoListValueChanged
        if(evt.getSource().equals(videoList) && !videoList.isSelectionEmpty()) {
            Video.doCurrentVideoChanged((Video)videoList.getSelectedValue(), this);
        }
}//GEN-LAST:event_videoListValueChanged

    private void buttonAddVideoMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_buttonAddVideoMouseReleased
        if(evt.getSource().equals(buttonAddVideo) && !videoList.isSelectionEmpty()) {
            for(Object o : videoList.getSelectedValues()) {
                if(o instanceof Video) {
                    ((VideoTableModel)videoTable1.getModel()).addVideo((Video)o);
                }
            }
            //While debugging
            //((VideoTableModel)videoTable1.getModel()).addVideo(Video.getCurrentVideo());
            videoTable1.updateProgressCellRenderer();
        }
    }//GEN-LAST:event_buttonAddVideoMouseReleased

    private void buttonStartDownloadingMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_buttonStartDownloadingMouseReleased
        for(Video v : ((VideoTableModel)videoTable1.getModel()).getVideos()) {
            if(v.getStatus() == Video.Status.WAITING) {
                try {
                    v.setDownloadProgressListener(((VideoTableModel)videoTable1.getModel()));
                    DownloadUrl du = new DownloadUrl(v.getUrl(), textDownloadDirectory.getText() + v.getTitle(), v);
                    du.start();
                } catch (IOException ex) {
                    Logger.getLogger(Jay9DownloaderView.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    }//GEN-LAST:event_buttonStartDownloadingMouseReleased

    private void buttonRemoveVideoMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_buttonRemoveVideoMouseReleased
        ((VideoTableModel)videoTable1.getModel()).removeVideoAtIndexes(videoTable1.getSelectedRows());
    }//GEN-LAST:event_buttonRemoveVideoMouseReleased
    
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JMenuItem aboutMenuItem;
    private javax.swing.JButton buttonAddVideo;
    private javax.swing.JButton buttonRemoveVideo;
    private javax.swing.JButton buttonStartDownloading;
    private javax.swing.JLabel creditLink1;
    private javax.swing.JLabel creditLink2;
    private javax.swing.JTextField filterTextField;
    private javax.swing.JMenu jMenu1;
    private javax.swing.JMenuItem jMenuItem1;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JLabel labelDownloadDirectory;
    private javax.swing.JLabel labelVideoComment;
    private javax.swing.JLabel labelVideoDetails;
    private javax.swing.JLabel labelVideoName;
    private javax.swing.JLabel labelVideoUrl;
    private javax.swing.JMenuBar menuBar;
    private javax.swing.JPanel panelAvailableVideos;
    private javax.swing.JPanel panelCurrentVideo;
    private javax.swing.JPanel panelMain;
    private javax.swing.JPanel panelSelectedVideos;
    private javax.swing.JProgressBar progressBar;
    private javax.swing.JLabel statusAnimationLabel;
    private javax.swing.JLabel statusMessageLabel;
    private javax.swing.JPanel statusPanel;
    private javax.swing.JTextField textDownloadDirectory;
    private javax.swing.JTextField textVideoComment;
    private javax.swing.JTextField textVideoDetails;
    private javax.swing.JTextField textVideoName;
    private javax.swing.JTextField textVideoUrl;
    private jay9downloader.VideoList videoList;
    private javax.swing.JScrollPane videoScroll;
    private jay9downloader.VideoTable videoTable1;
    // End of variables declaration//GEN-END:variables

    private final Timer messageTimer;
    private final Timer busyIconTimer;
    private final Icon idleIcon;
    private final Icon[] busyIcons = new Icon[15];
    private int busyIconIndex = 0;

    private JDialog aboutBox;
}
